/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dailynewsreader.view;

import dailynewsreader.controller.SubscriptionManager;
import dailynewsreader.model.LabelStorage;
import dailynewsreader.model.SearchFeed;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

/**
 * Az RSS olvasó fő panelje
 * @author Várhegyi Tamás
 */
public class RSSReaderPanel extends javax.swing.JPanel {

    /**
     * A megjelenéshez szükséges megszorítások
     */
    private GridBagConstraints constraints;
    
    /**
     * A feliratkozásokat kezelő modul
     */
    private SubscriptionManager subManager;
    
    /**
     * Van-e aktív folyamat
     */
    private boolean isInProgress;
    
    /**
     * Az állapotsor
     */
    private String statusBarLabel;
    
    /**
     * Aktuális feed címe
     */
    private String currentFeed;
    
    /**
     * Önmagára mutató
     */
    private RSSReaderPanel rssPanel;
    
    /**
     * Az rss olvasó panel konstruktora
     * @param subManager A feliratkozásokat kezelő modul
     */
    public RSSReaderPanel(final SubscriptionManager subManager) {
        initComponents();
        this.subManager = subManager;
        rssViewer.setLayout(new GridBagLayout()); 
        constraints = new GridBagConstraints();
        constraints.gridx = 0;            
        constraints.fill = GridBagConstraints.BOTH;
        constraints.gridwidth = 1;
        constraints.gridheight = 1;
        constraints.weightx = 1.0;            
        constraints.insets.bottom = 5;
        rssPanel = this;
        rssFeedFilter.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void changedUpdate(DocumentEvent e) {              
                
            }
    // implement the methods

            @Override
            public void insertUpdate(DocumentEvent e) {
               filtering();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
               filtering();
            }
        });
    }
    
    /**
     * A szűrést végző függvény, minden feedben keresünk
     */
    private void filtering(){
        if (!LabelStorage.FEED_FILTER_TEXT.equals(rssFeedFilter.getText())){
        ArrayList<String> rssFeeds = new ArrayList<>();
                for (dailynewsreader.model.RSSFeed feed : subManager.getFeeds()) {                    
                    if (feed.getTitle().toLowerCase().indexOf(rssFeedFilter.getText().trim().toLowerCase()) != -1)
                    rssFeeds.add(feed.getTitle());
                }
                rssPanel.setRSSFeedSelection(rssFeeds);
        }
    }
    
    /**
     * Beállítja a tree view-nak a
     * tartalmát.
     * 
     * @param nodes A tömbben tárolt fa struktúra
     */
    public void setRSSFeedSelection(ArrayList<String> feedList){   
        ArrayList<String> feedListWithNum = rssFeedSelectionConcatUnreadNum(feedList);
        ArrayList<String> favoriteFeeds = new ArrayList<>();
        Object[] feedObjects;
        
        for (int i = 0; i < feedListWithNum.size(); ++i) {
            if (subManager.getFeed(feedList.get(i)).isFavourite()){
                favoriteFeeds.add(feedListWithNum.get(i));                
            }
        }
         
        int containsFavoriteDir = 1;
        if (favoriteFeeds.size() > 0){
            for (String favoriteFeed : favoriteFeeds){
                feedListWithNum.remove(favoriteFeed);
            }
            favoriteFeeds.add(0, LabelStorage.FEED_SELECTION_FAV);
            feedObjects = new Object[feedListWithNum.size() + 2];
            containsFavoriteDir = 2;
        }
        else{
            feedObjects = new Object[feedListWithNum.size() + 1]; 
        }
        
        for(int i=0; i<feedObjects.length; i++){
            if (i == 0){
                feedObjects[i] = LabelStorage.FEED_SELECTION_NAME;
            }
            else if(i == 1 && containsFavoriteDir > 1){
                feedObjects[i] = favoriteFeeds.toArray();
            }
            else{
                feedObjects[i] = feedListWithNum.get(i-containsFavoriteDir);
            }
        }
        
        DefaultMutableTreeNode root = processHierarchy(feedObjects);
        this.rssFeedSelection.setModel(new DefaultTreeModel(root));
        if(containsFavoriteDir > 1) {
            this.rssFeedSelection.expandRow(0);
        }
    }
    
    /**
     * Új feed hozzáadása a feed-ek hierarchiájához
     * @param feedTitle Feed címe
     */
    public void addRSSFeedSelection(String feedTitle){        
        DefaultTreeModel model = (DefaultTreeModel) rssFeedSelection.getModel();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
        model.insertNodeInto(new DefaultMutableTreeNode(rssFeedSelectionConcatUnreadNum(feedTitle)), root, root.getChildCount());
        model.reload();
    }
    
    /**
     * Feed törlése a hierarchiából
     * @param feedTitle Feed címe
     * @param performRefresh Kell frissíteni az olvasót
     * @throws Exception 
     */
    public void removeRSSFeedSelection(String feedTitle, boolean performRefresh) throws Exception{        
        DefaultTreeModel model = (DefaultTreeModel) rssFeedSelection.getModel();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();         
        model.removeNodeFromParent(searchNode(feedTitle, root));
        
        if (root.getChildCount() > 0 && LabelStorage.FEED_SELECTION_FAV.equals(root.getFirstChild().toString())){             
            root = (DefaultMutableTreeNode)root.getFirstChild();
            if (root.getChildCount() == 0){
                model.removeNodeFromParent(root);
            }
        }        
        if (performRefresh) {
            rssFeedSelectionLoadFirstFeed();
        }
    }
    
    /**
     * A kedvencek közé felvétele egy feed-nek
     * @param feedTitle Feed címe
     * @throws Exception 
     */
    public void addFavoritesRSSFeedSelection(String feedTitle) throws Exception{
        DefaultTreeModel model = (DefaultTreeModel) rssFeedSelection.getModel();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();        
        if (!LabelStorage.FEED_SELECTION_FAV.equals(
            root.getFirstChild().toString()))
        {
            model.insertNodeInto(new DefaultMutableTreeNode(LabelStorage.FEED_SELECTION_FAV), root, 0);            
        }
        root = (DefaultMutableTreeNode)root.getFirstChild();
        model.insertNodeInto(new DefaultMutableTreeNode(rssFeedSelectionConcatUnreadNum(feedTitle)),root, root.getChildCount());
        this.removeRSSFeedSelection(feedTitle, false);
    }
    
    /**
     * Feed keresése a hierarchiában
     * @param nodeStr Feed címe
     * @param root A hierarchia gyökér eleme
     * @return A megtatlált feed elem
     */
     public DefaultMutableTreeNode searchNode(String nodeStr, DefaultMutableTreeNode root) {
        DefaultMutableTreeNode node;
        Enumeration e = root.breadthFirstEnumeration();
        while (e.hasMoreElements()) {          
          node = (DefaultMutableTreeNode) e.nextElement();
          String selectedFeedTitle = rssFeedSelectionSplitUnreadNum(nodeStr);
          String actualFeedTitle = rssFeedSelectionSplitUnreadNum(node.getUserObject().toString());
          if (selectedFeedTitle.equals(actualFeedTitle)) {
              return node;
          }
        }
        return null;
      }
    
     /**
      * Kedvencek közül feed eltávolítása
      * @param feedTitle Feed címe
      * @throws Exception 
      */
    private void removeFavoritesRSSFeedSelection(String feedTitle) throws Exception{
        DefaultTreeModel model = (DefaultTreeModel) rssFeedSelection.getModel();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();        
        if (!LabelStorage.FEED_SELECTION_FAV.equals(
            root.getFirstChild().toString()))
        {
            throw new Exception("Nem létező mappa");            
        }
        root = (DefaultMutableTreeNode)root.getFirstChild();
        model.removeNodeFromParent(searchNode(feedTitle, root));
        if (root.getChildCount() == 0)
            model.removeNodeFromParent(root);
        addRSSFeedSelection(feedTitle);
    }
    
    /**
     * Létrehozza a fának a hierarchiáját.
     * 
     * @param hierarchy tömbben megadott hierarchia
     * @return Az elkészült fa struktúra
     */
    private DefaultMutableTreeNode processHierarchy(Object[] hierarchy) {      
        DefaultMutableTreeNode node =
          new DefaultMutableTreeNode(hierarchy[0]);
        DefaultMutableTreeNode child;        
        
        for(int i=1; i<hierarchy.length; i++) {
          Object nodeSpecifier = hierarchy[i];
          if (nodeSpecifier instanceof Object[]) {
                child = processHierarchy((Object[])nodeSpecifier);
            }
          else {            
                child = new DefaultMutableTreeNode(nodeSpecifier);
            }
          node.add(child);
        }       
    
    return(node);
  }
    
    /**
     * Olvasatlan bejegyzések száma hozzáfűzése a feed nevéhez
     * @param feedTitle Feed címe
     * @return Összefűzött feed cím
     */
    private String rssFeedSelectionConcatUnreadNum(String feedTitle){
        int numOfUnreadEntries = subManager.getFeed(feedTitle).getUnreadEntryCount();
        if (numOfUnreadEntries > 0) {
            return feedTitle + " (" + numOfUnreadEntries + ")";
        }
        else {
            return feedTitle;
        }
    }
    
    /**
     * Olvasatlan bejegyzések száma hozzáfűzése a feed-ek nevéhez
     * @param feedList Feed-ek
     * @return Összefűzött feed címek
     */
    private ArrayList<String> rssFeedSelectionConcatUnreadNum(ArrayList<String> feedList){
        ArrayList<String> newFeedList = new ArrayList<>();
        for (String feedTitle : feedList){
            newFeedList.add(this.rssFeedSelectionConcatUnreadNum(feedTitle));
        }
        return newFeedList;
    }
    
    /**
     * Olvasatlan bejegyzések számának leválasztása a feed nevéről
     * @param feedTitleWithNum Feed címe olvasatlan számmal
     * @return Feed címe
     */
    private String rssFeedSelectionSplitUnreadNum(String feedTitleWithNum){
        if (feedTitleWithNum.lastIndexOf("(") > -1){
            String feedTitle = feedTitleWithNum.substring(0, feedTitleWithNum.lastIndexOf("(") - 1);
            return feedTitle;
        }
        return feedTitleWithNum;
    }
    
    /**
     * Olvasatlan bejegyzések számának leválasztása a feed-ek nevéről
     * @param feedListWithNum Feed-ek címe olvasatlan számmal
     * @return Feed-ek címe
     */
    private ArrayList<String> rssFeedSelectionSplitUnreadNum(ArrayList<String> feedListWithNum){
        ArrayList<String> newFeedList = new ArrayList<>();
        for (String feedTitle : feedListWithNum){
            newFeedList.add(this.rssFeedSelectionSplitUnreadNum(feedTitle));
        }
        return newFeedList;
    }
    
    /**
     * Beállítja a szöveget az RSS
     * megjelnítőbe.
     * @param t A beállítandó tartalom
     */
    public void setRSSViewerContent(dailynewsreader.model.RSSFeed feedModel) { 
        int processStatus;
        int actualIndex;
        rssViewer.removeAll();
        currentFeed = feedModel.getTitle();
        int nr = 0;
        RSSFeed feedView = new RSSFeed(this);
        feedView.setTitle(currentFeed);
        if (feedModel.isFavourite() != null){
            feedView.setIsFavorite(feedModel.isFavourite());  
            feedView.setButtons(true);
        } else {
            feedView.setButtons(false);
        }
        if (feedModel.hasLogo()) {
            feedView.setLogo(feedModel.getLogo().toHTML());
        }        
        feedView.setContent();
        constraints.gridy = nr;
        rssViewer.add(feedView, constraints);
        nr++;
        
        ArrayList<dailynewsreader.model.RSSEntry> feedModelList = feedModel.getEntries();
        int feedModelLength = feedModelList.size();
        
        for (dailynewsreader.model.RSSEntry entryModel : feedModelList) {
            // betöltő szöveg kiegészítése százalékkal
            actualIndex = feedModelList.indexOf(entryModel);
            processStatus = (int) (((double)actualIndex / (double)feedModelLength) * 100);
            refreshProgress(processStatus + "%");
            
            dailynewsreader.view.RSSEntry entryView = new RSSEntry();            
            entryView.setContent(entryModel);
            entryView.setLink(entryModel.getLink());           
            constraints.gridy = nr;
            rssScrollPaneForViewer.getVerticalScrollBar().setUnitIncrement(20);
            rssViewer.add(entryView, constraints);  
            nr++;
        }
        rssViewer.updateUI();
        //rssScrollPaneForViewer.getVerticalScrollBar().setValue(0);     
    }
    
    /**
     * Az RSS olvasó tartalmának beállítása. Feed-ek listája
     * @param feedModelList Feed-ek
     */
    public void setRSSViewerContent(ArrayList<dailynewsreader.model.RSSFeed> feedModelList){
        rssViewer.removeAll();
        currentFeed = "All";
        
        int nr = 0;
        for (dailynewsreader.model.RSSFeed feedModel: feedModelList){
            RSSFeed feedView = new RSSFeed(this);
            feedView.setTitle(feedModel.getTitle());
            feedView.setIsFavorite(feedModel.isFavourite());
            if (feedModel.hasLogo()){
                feedView.setLogo(feedModel.getLogo().toHTML());                
            }
            feedView.setContent();
            constraints.gridy = nr;
            rssViewer.add(feedView, constraints);
            nr++;
        }
        
        rssViewer.updateUI();
    }
    
    /**
     * Folyamatot jelző GUI elemek aktiválása
     * @param text Állapotsorba írandó szöveg
     */
    public void startProgress(String text){
        this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        switch (text) {
            case LabelStorage.PROGRESS_TITLE_ON_LOADING:
                this.statusBarLabel =  LabelStorage.PROGRESS_TITLE_ON_LOADING;
                break;
            case LabelStorage.PROGRESS_TITLE_ON_REFRESH:
                this.statusBarLabel = LabelStorage.PROGRESS_TITLE_ON_REFRESH;
                break;
            default:
                this.statusBarLabel = "";
                break;
        }
        this.setStatusBar(text);
        this.setIsInProgress(true);
    }
    
    /**
     * Folyamatot jelző GUI elemek frissítése
     * @param concat Állapotsorba írandó plusz szöveg
     */
    private void refreshProgress(String concat){
        if (this.isIsInProgress()){
            this.setStatusBar(this.getStatusBar() + " (" + concat + ")");
        }
    }
    
    /**
     * Folyamat aktív jelzése
     * @param isInProgress Aktív-e egy folyamat
     */
    private void setIsInProgress(boolean isInProgress){
        this.isInProgress = isInProgress;
    }
    
    /**
     * Van-e aktív folyamat
     * @return Igaz, ha van, hamis különben
     */
    private boolean isIsInProgress(){
        return this.isInProgress;
    }
    
    /**
     * Az állapotsor tartalmát lekérjük
     * @return Állapotsor tartalma
     */
    private String getStatusBar(){
        return this.statusBarLabel;
    }
    
    /**
     * Folyamat jelző GUI elemek deaktiválása
     */
    public void endProgress(){
        this.setCursor(Cursor.getDefaultCursor());
        this.setStatusBar("");
        this.setIsInProgress(false);
    }
    
    /**
     * Feliratkozás egy feed-re
     * @param text Feed url-je
     * @throws Exception 
     */
    public void addSubscription(String text) throws Exception{
        startProgress(LabelStorage.PROGRESS_TITLE_ON_LOADING);
        subManager.addSubscription(text);
        //this.refreshFeedSelection();
        ArrayList<dailynewsreader.model.RSSFeed> list = subManager.getFeeds();
        this.addRSSFeedSelection(list.get(list.size()-1).getTitle());
         if (currentFeed.equals("All")){
             this.refreshRSSFeedView();
         }
        endProgress();
    }
    
    /**
     * Leiratkozás egy feed-ről
     * @param text Feed címe
     * @throws Exception 
     */
    public void removeSubscription(String text) throws Exception{
        startProgress(LabelStorage.PROGRESS_TITLE_ON_LOADING);
        subManager.removeSubscription(subManager.getFeed(text));
        
        if (!currentFeed.equals("All")){
            this.removeRSSFeedSelection(text, true);
        }
        else{
            this.removeRSSFeedSelection(text, false);
            this.refreshRSSFeedView();
        }        
        endProgress();
    }
    
    public boolean renameFeed(String feedTitle, String text){    
        if (subManager.getFeed(text) != null){
            JOptionPane.showMessageDialog(this, "A megadott név már létezik! Kérem válaszzon másikat!", "Info", JOptionPane.INFORMATION_MESSAGE);
        } else if ("".equals(text.trim())){
            JOptionPane.showMessageDialog(this, "Érvénytelen név!", "Info", JOptionPane.INFORMATION_MESSAGE);
        } else {
            dailynewsreader.model.RSSFeed feed = subManager.getFeed(feedTitle);
            feed.setTitle(text);

            refreshFeedSelection();
            
            if ("All".equals(currentFeed)){
            switch(rssAllItemsButton.getSelectedIndex()){
                    case 0: setRSSViewerContent(subManager.getFeeds()); break;
                    case 1: setRSSViewerContent(selectFavoriteRSSFeeds(subManager.getFeeds())); break;
                }
            } else {
                setRSSViewerContent(subManager.getFeed(feed.getTitle()));
            }
           
            return true;
        }
        return false;
    }
    
    /**
     * Az RSS olvasó feed nézetének frissítése
     */
    private void refreshRSSFeedView(){
        JComboBox rssAllItems = this.rssAllItemsButton;
        if (rssAllItems != null){
            switch(rssAllItems.getSelectedIndex()){
                case 0: setRSSViewerContent(subManager.getFeeds()); break;
                case 1: setRSSViewerContent(selectFavoriteRSSFeeds(subManager.getFeeds())); break;
                default: break;
            }
        }
    }
    
    /**
     * Kedvencnek beállítás
     * @param text Feed címe
     * @throws Exception 
     */
    public void setFavorite(String text) throws Exception{
        dailynewsreader.model.RSSFeed feed = subManager.getFeed(text);
        if (feed.isFavourite()){
            feed.setIsFavorite(false);       
            removeFavoritesRSSFeedSelection(text);
        }
        else
        {
            feed.setIsFavorite(true);
            addFavoritesRSSFeedSelection(text);
        }
        if (this.currentFeed.equals("All")){
            this.refreshRSSFeedView();
        }
    }
    
    /**
     * Feed frissítése
     * @param feed Feed model
     */
    public void refreshFeed(dailynewsreader.model.RSSFeed feed){         
        setRSSViewerContent(feed);
    }
    
    /**
     * A feed-eket megjelenítő fa nézet frissítése
     */
    public void refreshFeedSelection(){
         ArrayList<String> rssFeeds = new ArrayList<>();
         for (dailynewsreader.model.RSSFeed feed : subManager.getFeeds()) {                      
           rssFeeds.add(feed.getTitle());
        }
        this.setRSSFeedSelection(rssFeeds);
    }
    
    /**
     * Az első feed betöltése a fa nézetből
     */
    private void rssFeedSelectionLoadFirstFeed(){
        DefaultTreeModel model = (DefaultTreeModel) rssFeedSelection.getModel();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); 
        if (root.getChildCount() != 0){
            String selectedFeed = rssFeedSelectionSplitUnreadNum(root.getFirstLeaf().toString());                     
            dailynewsreader.model.RSSFeed feed = subManager.getFeed(selectedFeed);
            setRSSViewerContent(feed);
        }
        else
        {
            rssViewer.removeAll();
        }
    }
    
    /**
     * A GUI elemek engedélyezése, vagy tiltása
     * @param enabled Engedélyezett-e
     */
    @Override
    public void setEnabled(boolean enabled){
        super.setEnabled(enabled);
        for(Component c : this.getComponents()){
            c.setEnabled(enabled);
        }
    }
    
    /**
     * Az állapotsor beállítása
     * @param text 
     */
    private void setStatusBar(String text){
        this.rssStatusBar.setText(text);
    }
    
    /**
     * Egy feed model megkeresése
     * @param title Feed címe
     * @return Keresett feed model
     */
    public dailynewsreader.model.RSSFeed getFeed(String title){
        return subManager.getFeed(title);
    }
    
    /**
     * Az rss feed-eket megjelenítő fa nézetre való kattintás kezelése
     * @param me 
     */
    private void rssFeedSelectionClicked(MouseEvent me) {
        startProgress(LabelStorage.PROGRESS_TITLE_ON_LOADING);
        TreePath tp = rssFeedSelection.getPathForLocation(me.getX(), me.getY());     
        if (tp != null){
            String selectedFeedWithNum = tp.getLastPathComponent().toString();
            String selectedFeed = rssFeedSelectionSplitUnreadNum(selectedFeedWithNum);
            if (!LabelStorage.FEED_SELECTION_FAV.equals(selectedFeed)){
                this.refreshProgress("Feed feldolgozása");
                dailynewsreader.model.RSSFeed feed = subManager.getFeed(selectedFeed);
                setRSSViewerContent(feed);
            }
        }
        endProgress();        
     }
     
    /**
     * A kedvencnek jelölt feed-ek kiválasztása
     * @param feedList Feed-ek
     * @return Kedvenc feed-ek
     */
     private ArrayList<dailynewsreader.model.RSSFeed> selectFavoriteRSSFeeds(ArrayList<dailynewsreader.model.RSSFeed> feedList){
         ArrayList<dailynewsreader.model.RSSFeed> favoriteFeedList = new ArrayList<>();
         for (dailynewsreader.model.RSSFeed feedModel : feedList){
             if (feedModel.isFavourite()){
                 favoriteFeedList.add(feedModel);
             }
         }        
         return favoriteFeedList;
     }
     
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        rssScrollPaneForSelection = new javax.swing.JScrollPane();
        rssFeedSelection = new javax.swing.JTree();
        rssScrollPaneForViewer = new javax.swing.JScrollPane();
        rssViewer = new javax.swing.JPanel();
        rssSubscribeButton = new javax.swing.JButton();
        rssRefreshButton = new javax.swing.JButton();
        rssAllMarkAsReadButton = new javax.swing.JButton();
        rssAllItemsButton = new javax.swing.JComboBox();
        rssStatusBar = new java.awt.Label();
        rssFeedFilter = new javax.swing.JTextField();
        rssFeedSearch = new javax.swing.JTextField();

        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root");
        rssFeedSelection.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
        rssFeedSelection.setRootVisible(false);
        rssFeedSelection.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                rssFeedSelection_Clicked(evt);
            }
        });
        rssFeedSelection.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
                rssFeedSelectionValueChanged(evt);
            }
        });
        rssScrollPaneForSelection.setViewportView(rssFeedSelection);

        rssScrollPaneForViewer.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                rssScrollPaneForViewerMouseWheelMoved(evt);
            }
        });

        rssViewer.setMaximumSize(rssViewer.getPreferredSize());

        javax.swing.GroupLayout rssViewerLayout = new javax.swing.GroupLayout(rssViewer);
        rssViewer.setLayout(rssViewerLayout);
        rssViewerLayout.setHorizontalGroup(
            rssViewerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 730, Short.MAX_VALUE)
        );
        rssViewerLayout.setVerticalGroup(
            rssViewerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 446, Short.MAX_VALUE)
        );

        rssScrollPaneForViewer.setViewportView(rssViewer);

        rssSubscribeButton.setBackground(new java.awt.Color(255, 0, 0));
        rssSubscribeButton.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
        rssSubscribeButton.setForeground(new java.awt.Color(255, 255, 255));
        rssSubscribeButton.setText(LabelStorage.SUBSCRIPTION_BUTTON_TEXT);
        rssSubscribeButton.setToolTipText(LabelStorage.SUBSCRIPTION_BUTTON_TOOLTIP);
        rssSubscribeButton.setFocusable(false);
        rssSubscribeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rssSubscribeButtonActionPerformed(evt);
            }
        });

        rssRefreshButton.setBackground(new java.awt.Color(255, 255, 255));
        rssRefreshButton.setText(LabelStorage.REFRESH_BUTTON_TEXT);
        rssRefreshButton.setToolTipText(LabelStorage.REFRESH_BUTTON_TOOLTIP);
        rssRefreshButton.setFocusable(false);
        rssRefreshButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rssRefreshButtonActionPerformed(evt);
            }
        });

        rssAllMarkAsReadButton.setBackground(new java.awt.Color(255, 255, 255));
        rssAllMarkAsReadButton.setText(LabelStorage.ALL_READ_BUTTON_TEXT);
        rssAllMarkAsReadButton.setToolTipText(LabelStorage.ALL_READ_BUTTON_TOOLTIP);
        rssAllMarkAsReadButton.setFocusable(false);
        rssAllMarkAsReadButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rssAllMarkAsReadButtonActionPerformed(evt);
            }
        });

        rssAllItemsButton.setModel(new DefaultComboBoxModel(new Object[]{LabelStorage.COMBOBOX_LABEL_ALL, LabelStorage.COMBOBOX_LABEL_FAV}));
        rssAllItemsButton.setToolTipText("");
        rssAllItemsButton.setFocusable(false);
        rssAllItemsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                rssAllItemsButtonActionPerformed(evt);
            }
        });

        rssFeedFilter.setText(LabelStorage.FEED_FILTER_TEXT);
        rssFeedFilter.setToolTipText(LabelStorage.FEED_FILTER_TOOLTIP);
        rssFeedFilter.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                rssFeedFilterMouseClicked(evt);
            }
        });
        rssFeedFilter.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                rssFeedFilterFocusLost(evt);
            }
        });

        rssFeedSearch.setText(LabelStorage.SEARCH_FEED_TEXT);
        rssFeedSearch.setToolTipText(LabelStorage.SEARCH_FEED_TOOLTIP);
        rssFeedSearch.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                rssFeedSearchMouseClicked(evt);
            }
        });
        rssFeedSearch.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                rssFeedSearchFocusLost(evt);
            }
        });
        rssFeedSearch.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                rssFeedSearchKeyPressed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(rssStatusBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(layout.createSequentialGroup()
                                    .addGap(48, 48, 48)
                                    .addComponent(rssSubscribeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 116, javax.swing.GroupLayout.PREFERRED_SIZE))
                                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                    .addGap(10, 10, 10)
                                    .addComponent(rssFeedFilter, javax.swing.GroupLayout.PREFERRED_SIZE, 200, javax.swing.GroupLayout.PREFERRED_SIZE)))
                            .addGroup(layout.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(rssScrollPaneForSelection, javax.swing.GroupLayout.PREFERRED_SIZE, 200, javax.swing.GroupLayout.PREFERRED_SIZE)))
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(rssRefreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 84, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(18, 18, 18)
                                .addComponent(rssAllItemsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(18, 18, 18)
                                .addComponent(rssAllMarkAsReadButton)
                                .addGap(18, 18, 18)
                                .addComponent(rssFeedSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addComponent(rssScrollPaneForViewer, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(52, 52, 52)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(rssSubscribeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 59, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(rssRefreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(rssAllItemsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(rssAllMarkAsReadButton, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE))))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGap(73, 73, 73)
                        .addComponent(rssFeedSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addGap(37, 37, 37)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(rssFeedFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(rssScrollPaneForSelection))
                    .addComponent(rssScrollPaneForViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 423, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(rssStatusBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(6, 6, 6))
        );
    }// </editor-fold>//GEN-END:initComponents

    /**
     * Frissítése gombra kattintás kezelése
     * @param evt 
     */
    private void rssRefreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rssRefreshButtonActionPerformed
        if (!currentFeed.equals("All")){
            this.startProgress(LabelStorage.PROGRESS_TITLE_ON_REFRESH);
            this.refreshProgress("Feed újratöltése");
            try {
                subManager.refreshFeed(subManager.getFeed(currentFeed));
            } catch (Exception ex) {
                Logger.getLogger(RSSReaderPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
            refreshFeed(subManager.getFeed(currentFeed));    
            this.endProgress();
        }
    }//GEN-LAST:event_rssRefreshButtonActionPerformed

    /**
     * Feliratkozás gombra kattintás kezelése
     * @param evt 
     */
    private void rssSubscribeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rssSubscribeButtonActionPerformed
        RSSSubscriptionFrame frame = new RSSSubscriptionFrame(this);
        frame.setLocationRelativeTo(this);
        frame.setVisible(true);
    }//GEN-LAST:event_rssSubscribeButtonActionPerformed

    /**
     * Rss feed-eket tartalmazó fa nézetre kattintás kezelése
     * @param evt 
     */
    private void rssFeedSelection_Clicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rssFeedSelection_Clicked
        if (evt.getButton() == MouseEvent.BUTTON1) {
            rssFeedSelectionClicked(evt);       
        } else if (evt.getButton() == MouseEvent.BUTTON3) {
            
            RSSRenameFrame frame = new RSSRenameFrame(this);
            frame.setLocationRelativeTo(this);
            frame.setVisible(true);
            
            TreePath tp = rssFeedSelection.getPathForLocation(evt.getX(), evt.getY());
            if (tp != null){
                String selectedFeedWithNum = tp.getLastPathComponent().toString();
                String selectedFeed = rssFeedSelectionSplitUnreadNum(selectedFeedWithNum);
                    if (!LabelStorage.FEED_SELECTION_FAV.equals(selectedFeed)){
                        frame.setName(selectedFeed);                
                    }
            }
        }
        
    }//GEN-LAST:event_rssFeedSelection_Clicked

    /**
     * Összes olvasottnak jelölés gombra kattintás kezelése
     * @param evt 
     */
    private void rssAllMarkAsReadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rssAllMarkAsReadButtonActionPerformed
        if (!currentFeed.equals("All")){
            this.startProgress(LabelStorage.PROGRESS_TITLE_ON_LOADING);
            this.refreshProgress("Bejegyzések olvasottnak jelölése");
            subManager.getFeed(currentFeed).markAllAsRead();        
            refreshFeed(subManager.getFeed(currentFeed));
            refreshFeedSelection();
            this.endProgress();
        }
        
    }//GEN-LAST:event_rssAllMarkAsReadButtonActionPerformed

    /**
     * Összes elem legördülő listára kattintás kezelése
     * @param evt 
     */
    private void rssAllItemsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rssAllItemsButtonActionPerformed
        JComboBox rssAllItems = (JComboBox)evt.getSource();
        if (rssAllItems != null){
            switch(rssAllItems.getSelectedIndex()){
                case 0: setRSSViewerContent(subManager.getFeeds()); break;
                case 1: setRSSViewerContent(selectFavoriteRSSFeeds(subManager.getFeeds())); break;
            }
        }
    }//GEN-LAST:event_rssAllItemsButtonActionPerformed

    /**
     * Az RSS olvasó tartalmának görgetésének kezelése
     * @param evt 
     */
    private void rssScrollPaneForViewerMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_rssScrollPaneForViewerMouseWheelMoved
        Component[] comps = this.rssViewer.getComponents();
        for (Component c: comps){
            if (c instanceof RSSEntry){
                RSSEntry entry = (RSSEntry) c;
                Rectangle r = entry.getVisibleRect();
                if (r.getSize().equals(c.getSize())) {                   
                   entry.setIsRead(true);
                   refreshFeedSelection();
                } else if (r.isEmpty()) {
                   // nem látszik
                } else {
                  // részben látszik
                }
            }
        }
    }//GEN-LAST:event_rssScrollPaneForViewerMouseWheelMoved

    /**
     * A feed-eket tartalmazó fa nézet változásának kezelése
     * @param evt 
     */
    private void rssFeedSelectionValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_rssFeedSelectionValueChanged
       this.rssFeedSelection.expandRow(0);
    }//GEN-LAST:event_rssFeedSelectionValueChanged

    /**
     * Feed szűrőre kattintás
     * @param evt 
     */
    private void rssFeedFilterMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rssFeedFilterMouseClicked
        this.rssFeedFilter.setText("");
    }//GEN-LAST:event_rssFeedFilterMouseClicked

    /**
     * Kereső mezőben való gombnyomás
     * @param evt 
     */
    private void rssFeedSearchKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_rssFeedSearchKeyPressed
        if (KeyEvent.VK_ENTER == evt.getKeyCode() && !"".equals(rssFeedSearch.getText().trim()))
        {            
            ArrayList<dailynewsreader.model.RSSFeed> feeds = subManager.getFeeds();
            ArrayList<dailynewsreader.model.RSSEntry> entries = new ArrayList<dailynewsreader.model.RSSEntry>();
            for (dailynewsreader.model.RSSFeed feed : feeds) {    
                entries.addAll(subManager.getFeed(feed.getTitle()).getEntriesFor(rssFeedSearch.getText().trim()));
            }  
            
            SearchFeed resultFeed = new SearchFeed(entries, rssFeedSearch.getText().trim());
            this.setRSSViewerContent(resultFeed);
        }  
    }//GEN-LAST:event_rssFeedSearchKeyPressed

    /**
     * Keresőmezőben való kattintás
     * @param evt 
     */
    private void rssFeedSearchMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rssFeedSearchMouseClicked
        this.rssFeedSearch.setText("");
    }//GEN-LAST:event_rssFeedSearchMouseClicked

    private void rssFeedFilterFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_rssFeedFilterFocusLost
        if (rssFeedFilter.getText().equals("")){
            rssFeedFilter.setText(LabelStorage.FEED_FILTER_TEXT);
        }
    }//GEN-LAST:event_rssFeedFilterFocusLost

    private void rssFeedSearchFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_rssFeedSearchFocusLost
        if (rssFeedSearch.getText().equals("")){
            rssFeedSearch.setText(LabelStorage.SEARCH_FEED_TEXT);
        }
    }//GEN-LAST:event_rssFeedSearchFocusLost

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox rssAllItemsButton;
    private javax.swing.JButton rssAllMarkAsReadButton;
    private javax.swing.JTextField rssFeedFilter;
    private javax.swing.JTextField rssFeedSearch;
    private javax.swing.JTree rssFeedSelection;
    private javax.swing.JButton rssRefreshButton;
    private javax.swing.JScrollPane rssScrollPaneForSelection;
    private javax.swing.JScrollPane rssScrollPaneForViewer;
    private java.awt.Label rssStatusBar;
    private javax.swing.JButton rssSubscribeButton;
    private javax.swing.JPanel rssViewer;
    // End of variables declaration//GEN-END:variables
}